//Linux C plus plus file
/************************************************************************
*
*
*       			FileName:commandTree.cpp
*
*         			Author.wzj
*
*       			Email:345517039@qq.com
*
*      	    		Create:2017-06-22 23:32:17
*
*      		    	Description:-
*
*
*************************************************************************/
#include "commandTree.h"

/**
 * @brief 
 *
 * @param cmd
 *
 * @return 
 */
int commandTree::insertCmdTreeNode(int cmdType, char * cmd){
	int ret = RET::FAIL;
	std::vector<char *>  cmdnode; //命令节点;
	assert(cmd != NULL);
	if( NULL == root ){
		//目前先用malloc 后期会用内存池来
		root = (struct commandTree_st *)malloc(sizeof(struct commandTree_st));
		INIT_TREE_NODE(root);
	}
	struct commandTree_st * node = (struct commandTree_st *)malloc(sizeof(struct commandTree_st));
	if ( NULL == node)
	{
		//打印错误;
		return ret;

	}
	//这边是要判断的,先不写 后期这边要判断, 并且发生错误的时候 写入日志;
	INIT_TREE_NODE(node);
#define BUF_SIZE 100
	char pBuf[BUF_SIZE];
	ret = Utils::FormatCmd(cmd, pBuf);
	if ( ret == RET::FAIL)
	{
		//打印错误;
		return ret;
	}
	//这边搞个递归函数来实现命令的搜索和识别;
	splitCmdIntoTmpVector(pBuf, cmdnode);
	//搜索;
	searchCmdTreeNode(cmdType, cmdnode);
	return RET::SUCCESS;
}


/**
 * @brief 
 *
 * @param cmd
 * @param vec
 *
 * @return 
 */
int commandTree::splitCmdIntoTmpVector(char * cmd, std::vector<char *> &vec){
	if ( NULL == cmd)
	{
		return RET::FAIL;
	}
	size_t len = strlen(cmd);
	char pBuf[len +  1];
	memset(pBuf, '\0', len + 1);
	memcpy(pBuf, cmd, len);
	const char * delim = "-";
	char * str = strtok(pBuf, delim);
	if(NULL == str){
		//error;
		DEBUG_TRACE(2, ("[ ERROR ]STRTOK FUNCTION OCCUR ERROR!\n"));
		return RET::FAIL;
	}
	vec.push_back(strdup(str));
	while((str = strtok(NULL, delim)))
	{
		vec.push_back(strdup(str));
	}
	return RET::SUCCESS;
}


/**
 * @brief 
 *
 * @param vec
 *
 * @return 
 */
int commandTree::searchCmdTreeNode(int CmdType, std::vector<char *> &vec){
	int ret = RET::FAIL;
  	unsigned int index = 0;
	__gnu_cxx::hash_map<char *, struct commandTree_st *>::iterator it  = Index.begin();
	for( ; it != Index.end(); it++){
		ret = strncmp(it->first,vec[index],strlen(vec[index]));
		if(ret == 0 && (strlen(it->first) == strlen(vec[index]))){	
			struct commandTree_st * node = it->second;
			if(node->tailFlag == true)
			{
				node->command_ext(node->arg);
				return RET::SUCCESS;
			}else{ 
				index ++;
				ret = matchCmd(CmdType, node, vec, index);
			}
			return ret;
		}
	}
	//丢入hashmap;
	if (CmdType != CMD_CHECK)
	{
		ret = createCmdTreeNode(CmdType,root,vec,index);
		return ret;
	}
	return RET::FAIL;
}


/**
 * @brief   
 *
 * @param node
 * @param vec
 * @param index
 *
 * @return 
 */
int commandTree::matchCmd(int CmdType, struct commandTree_st * node, std::vector<char *> &vec, unsigned int index ){
	int ret = RET::FAIL;
	if ( NULL == node || index >= vec.size())
	{
		return RET::FAIL;
	}
	struct commandTree_st * temp = node->right;
	while(temp){
		ret = strncmp(temp->command,vec[index],strlen(vec[index]));
		if(ret == 0 && (strlen(temp->command) == strlen(vec[index]))){ //继续匹配;
			if(CmdType == CMD_CHECK && temp->tailFlag== true)
			{
				temp->command_ext(temp->arg);
				return RET::SUCCESS;
			}else{
				ret = matchCmd(CmdType, temp, vec, index+1);
				break;
			}
		}
		temp = temp->next;
	}
	if( ret != RET::SUCCESS && CmdType != CMD_CHECK){ //命令树初始化阶段
		ret = createCmdTreeNode(CmdType, node, vec, index);
		return ret;
	}
	return ret == RET::SUCCESS ? ret : RET::FAIL;
}


/**
 * @brief 
 *
 * @param node
 * @param vec
 * @param index
 *
 * @return 
 */
int commandTree::createCmdTreeNode(int CmdType, struct commandTree_st *node, std::vector<char *> &vec, unsigned int index){
	int iRet = RET::FAIL;
	if ( NULL  == node )
	{
		return iRet;	
	}
	__gnu_cxx::hash_map<int, struct CmdFunctionSet> cmdSet = utils.getCmdHashOpt();
	if (index  == vec.size()){
		return RET::SUCCESS;
	}
	//到时候从内存池里获取内存;
	struct commandTree_st * pNode = (struct commandTree_st *)malloc(sizeof(struct commandTree_st));
	INIT_TREE_NODE(pNode);
	if(index == vec.size() - 1){
		pNode->tailFlag = true;
	    pNode->command_ext = cmdSet[CmdType].registerFunc; //注册一把;
	}
	pNode->command=strdup(vec[index]);
	if( NULL == node->right){
		node->right=node->left = pNode;
	}else{
		node->left->next = pNode;
		pNode->front = node->left;
		node->left= pNode;
	}
	if(index == 0){
		Index.insert(std::pair<char *, struct commandTree_st *>(vec[index],pNode));
	}
	iRet = createCmdTreeNode(CmdType, pNode, vec, index+1);
	return iRet;
}


/**
 * @brief 
 *
 * @param node
 */
void commandTree::displayCmdTree(struct commandTree_st *node){
	if ( NULL == node)
	{
		DEBUG_TRACE(2,("IN FUNCTION:%s GET PARAMETER ERROR!\n",__func__));
		return ;
	}
	struct commandTree_st *temp = node->right;
	while(temp){
		DEBUG_TRACE(2,("NODE:%p, COMMAND:%s \n", temp, temp->command));
		if (temp->command_ext){
			DEBUG_TRACE(2,("NODE:%p, COMMAND:%s function:%p\n", temp, temp->command, temp->command_ext));
		}
		displayCmdTree(temp);
		temp = temp->next;
	}
}


/**
 * @brief 
 *
 * @param cmd
 *
 * @return 
 */
int commandTree::parseCmd(char * cmd, std::vector<char *> &vecCmd){
	int iRet = RET::FAIL;
	if ( NULL == cmd)
	{
		return iRet;
	}
	if ( vecCmd.size() != 0 )
	{
		vecCmd.clear();
	}
#define BUF_SIZE 100
	char pBuf[BUF_SIZE];
	iRet = Utils::FormatCmd(cmd, pBuf); 
   	if ( iRet == RET::FAIL )
	{
		//打印一个错误
		return iRet;
	}
	//这边实际上要对命令行进行检查.
	iRet = splitCmdIntoTmpVector(pBuf,vecCmd);
	if (iRet == RET::FAIL)
	{
		//检查失败;
		DEBUG_TRACE(2,("[ ERROR ]SPLIT CMD INTO TMP VECTOR ERROR!\n"));
		return iRet;
	}
	iRet = searchCmdTreeNode(CMD_CHECK, vecCmd);
	if ( iRet == RET::FAIL ){
		DEBUG_TRACE(2,("[ ERROR ]USER INPUT UNKNOWN CMD!\n"));
		return iRet;
	}
	//进行命令检查;
	return iRet;
}

